package com.iotechn.unimall.admin.api.distribution;

import com.baomidou.mybatisplus.mapper.EntityWrapper;
import com.github.binarywang.wxpay.bean.entpay.EntPayRequest;
import com.github.binarywang.wxpay.bean.entpay.EntPayResult;
import com.github.binarywang.wxpay.exception.WxPayException;
import com.github.binarywang.wxpay.service.WxPayService;
import com.iotechn.unimall.biz.service.distribution.DistributionBizService;
import com.iotechn.unimall.core.exception.AdminServiceException;
import com.iotechn.unimall.core.exception.AppServiceException;
import com.iotechn.unimall.core.exception.ExceptionDefinition;
import com.iotechn.unimall.core.exception.ServiceException;
import com.iotechn.unimall.data.component.LockComponent;
import com.iotechn.unimall.data.domain.DistributionBalanceDetailDO;
import com.iotechn.unimall.data.domain.DistributionDO;
import com.iotechn.unimall.data.domain.DistributionWithdrawDO;
import com.iotechn.unimall.data.domain.UserDO;
import com.iotechn.unimall.data.dto.DistributionWithdrawDTO;
import com.iotechn.unimall.data.dto.UserDTO;
import com.iotechn.unimall.data.enums.DistributionWithdrawStatusType;
import com.iotechn.unimall.data.enums.UserLoginType;
import com.iotechn.unimall.data.mapper.DistributionBalanceDetailMapper;
import com.iotechn.unimall.data.mapper.DistributionMapper;
import com.iotechn.unimall.data.mapper.DistributionWithdrawMapper;
import com.iotechn.unimall.data.mapper.UserMapper;
import com.iotechn.unimall.data.model.Page;
import com.iotechn.unimall.data.util.SessionUtil;
import org.apache.ibatis.session.RowBounds;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.Date;
import java.util.List;

@Service
public class AdminDistributionWithdrawServiceImpl implements AdminDistributionWithdrawService {

    @Autowired
    private UserMapper userMapper;

    @Autowired
    private DistributionWithdrawMapper distributionWithdrawMapper;
    @Autowired
    private DistributionBizService distributionBizService;

    @Autowired
    private DistributionMapper distributionMapper;

    @Autowired
    private DistributionBalanceDetailMapper distributionBalanceDetailMapper;

    @Autowired
    private LockComponent lockComponent;

    @Autowired
    private WxPayService wxPayService;

    @Value("${com.iotechn.unimall.wx.mini.app-id}")
    private String wxMiNiAppid;

    @Value("${com.iotechn.unimall.wx.app.app-id}")
    private String wxAppAppid;

    private static final String LOCK_DISTRIBUTION_WITHDRAW = "LOCK_DISTRIBUTION_WITHDRAW_";

    private static final Logger logger = LoggerFactory.getLogger(AdminDistributionWithdrawServiceImpl.class);

    @Override
    public Page<DistributionWithdrawDTO> list(Integer page, Integer limit, Long adminId) throws ServiceException {
        EntityWrapper<DistributionWithdrawDO> wrapper = new EntityWrapper<>();
        List<DistributionWithdrawDTO> withdrawPage = distributionWithdrawMapper.getWithdrawPage(null, (page - 1) * limit, limit);
        Integer count = distributionWithdrawMapper.selectCount(wrapper);
        return new Page<>(withdrawPage, page, limit, count);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public String audit(Long withdrawId, Integer status, String ip, Long adminId) throws ServiceException {
        String key = LOCK_DISTRIBUTION_WITHDRAW + withdrawId;
        if (lockComponent.tryLock(key, 120)) {
            try {
                DistributionWithdrawDO withdrawDO = distributionWithdrawMapper.selectById(withdrawId);
                if (withdrawDO != null) {
                    if (withdrawDO.getStatus() != DistributionWithdrawStatusType.WAIT_AUDIT.getCode()) {
                        throw new AdminServiceException(ExceptionDefinition.DISTRIBUTION_WITHDRAW_DATA_ERROR);
                    }
                    Date now = new Date();
                    if (DistributionWithdrawStatusType.ALLOW.getCode() == status) {
                        DistributionDO distributionDO = distributionMapper.selectByIdForUpdate(withdrawDO.getDistributionId());
                        Integer sum = withdrawDO.getSum();
                        /*DistributionBalanceDetailDO lastDetail = distributionBalanceDetailMapper.getDistributionUserLastForUpdate(withdrawDO.getDistributionId());
                        //判断两个数据是否一致
                        if (!lastDetail.getFreezeBalance().equals(distributionDO.getFreezeBalance()) || !lastDetail.getBalance().equals(distributionDO.getBalance())) {
                            throw new AppServiceException(ExceptionDefinition.DISTRIBUTION_YOUR_DATA_NOT_CONSTANCY);
                        }*/
                        //校验余额是否充足
                        /*if (distributionDO.getBalance() < sum) {
                            throw new AppServiceException(ExceptionDefinition.DISTRIBUTION_BALANCE_NOT_ENOUGH);
                        }*/
                        //
                        //开始提现
                        //1.扣减余额
                        //distributionMapper.decBalance(distributionDO.getId(), sum);
                        //2.增加明细表
                        DistributionBalanceDetailDO balanceDetailDO = new DistributionBalanceDetailDO();
                        balanceDetailDO.setFreezeBalance(distributionDO.getFreezeBalance());
                        balanceDetailDO.setFreezeBalanceDelta(0);
                        balanceDetailDO.setBalance(distributionDO.getBalance() - sum);
                        balanceDetailDO.setRealBalance(distributionDO.getRealBalance() - sum);
                        balanceDetailDO.setTotalBalance(distributionDO.getBalance());
                        balanceDetailDO.setTotalRealBalance(distributionDO.getRealBalance());
                        balanceDetailDO.setBalanceDelta(-sum);
                        balanceDetailDO.setRealBalanceDelta(-sum);
                        balanceDetailDO.setOrderNo("");
                        balanceDetailDO.setDescription("佣金提现-RMB" + sum / 100.0);
                        balanceDetailDO.setGmtUpdate(now);
                        balanceDetailDO.setGmtCreate(now);
                        balanceDetailDO.setDistributionId(withdrawDO.getDistributionId());
                        distributionBalanceDetailMapper.insert(balanceDetailDO);
                        //3.增加提现记录
                        DistributionWithdrawDO updateWithdrawDO = new DistributionWithdrawDO();
                        updateWithdrawDO.setStatus(DistributionWithdrawStatusType.ALLOW.getCode());
                        updateWithdrawDO.setGmtUpdate(now);
                        if (distributionWithdrawMapper.update(updateWithdrawDO,
                                new EntityWrapper<DistributionWithdrawDO>()
                                        .eq("id", withdrawDO.getId())
                                        .eq("status", DistributionWithdrawStatusType.WAIT_AUDIT.getCode())) <= 0) {
                            throw new AdminServiceException(ExceptionDefinition.DISTRIBUTION_WITHDRAW_DATA_ERROR);
                        }
                        //4.发起微信转账
                        EntPayRequest entPayRequest = new EntPayRequest();
                        UserDO user = userMapper.selectById(distributionDO.getUserId());
                        entPayRequest.setOpenid(user.getOpenId());
                        entPayRequest.setCheckName("NO_CHECK");
                        entPayRequest.setReUserName(distributionDO.getRealname());
                        entPayRequest.setPartnerTradeNo(withdrawDO.getTradeNo());
                        entPayRequest.setAmount(sum);
                        entPayRequest.setDescription("睢宁菜系佣金提现");
                        entPayRequest.setSpbillCreateIp(ip);
                        if (user.getLoginType() == UserLoginType.MP_WEIXIN.getCode()) {
                            entPayRequest.setAppid(wxMiNiAppid);
                        } else if (user.getLoginType() == UserLoginType.APP_WEIXIN.getCode()) {
                            entPayRequest.setAppid(wxAppAppid);
                        } else {
                            throw new AppServiceException(ExceptionDefinition.DISTRIBUTION_CANNOT_LOCATE_USER_WECHAT);
                        }
                        EntPayResult entPayResult = null;
                        try {
                            entPayResult = wxPayService.getEntPayService().entPay(entPayRequest);
                            logger.info("entPayResult : " + entPayResult);
                            return "ok";
                        } catch (WxPayException e) {
                            logger.error("[微信Api提现] 异常", e);
                            throw new AppServiceException(ExceptionDefinition.buildVariableException(ExceptionDefinition.THIRD_PART_CUSTOM_SERVICE_EXCEPTION, e.getErrCodeDes()));
                        }
                    } else if (DistributionWithdrawStatusType.DENY.getCode() == status) {
                        //当拒绝用户提现，余额退回给用户同时生成一条退款记录
                        DistributionDO distributionDO = distributionMapper.selectByIdForUpdate(withdrawDO.getDistributionId());
                        Integer sum = withdrawDO.getSum();
                        DistributionBalanceDetailDO balanceDetailDO = new DistributionBalanceDetailDO();
                        balanceDetailDO.setFreezeBalance(distributionDO.getFreezeBalance());
                        balanceDetailDO.setFreezeBalanceDelta(0);
                        balanceDetailDO.setBalance(distributionDO.getBalance() + sum);
                        balanceDetailDO.setBalanceDelta(sum);
                        balanceDetailDO.setOrderNo("");
                        balanceDetailDO.setDescription("佣金拒绝提现退回-RMB" + sum / 100.0);
                        balanceDetailDO.setGmtUpdate(now);
                        balanceDetailDO.setGmtCreate(now);
                        balanceDetailDO.setDistributionId(withdrawDO.getDistributionId());
                        distributionBalanceDetailMapper.insert(balanceDetailDO);
                        Integer returnReal = distributionBizService.getReturnReal(null, distributionDO, sum);
                        distributionMapper.incBalance(distributionDO.getId(),sum,returnReal);
                        DistributionWithdrawDO updateWithdrawDO = new DistributionWithdrawDO();
                        updateWithdrawDO.setStatus(DistributionWithdrawStatusType.DENY.getCode());
                        updateWithdrawDO.setGmtUpdate(now);
                        if (distributionWithdrawMapper.update(updateWithdrawDO,
                                new EntityWrapper<DistributionWithdrawDO>()
                                        .eq("id", withdrawDO.getId())
                                        .eq("status", DistributionWithdrawStatusType.WAIT_AUDIT.getCode())) > 0) {
                            return "ok";
                        }
                        throw new AdminServiceException(ExceptionDefinition.DISTRIBUTION_WITHDRAW_DATA_ERROR);
                    }
                }
                throw new AdminServiceException(ExceptionDefinition.DISTRIBUTION_WITHDRAW_DATA_ERROR);
            } catch (ServiceException e) {
                throw e;
            } catch (Exception e) {
                logger.error("[分销提现] 异常", e);
                throw new AdminServiceException(ExceptionDefinition.ADMIN_UNKNOWN_EXCEPTION);
            } finally {
                lockComponent.retree(key);
            }
        }
        throw new AdminServiceException(ExceptionDefinition.SYSTEM_BUSY);
    }
}
